/*************  技术支持与购买说明    **************
产品主页：http://tw51.haohaodada.com
淘宝搜索：天问51，可购买。目前基础版99元，带彩屏标准备版149元，旗舰版299
技术支持QQ群一：1138055784
******************************************/

#ifndef __VL53L0X_H
#define __VL53L0X_H

#if defined (_C51)
#include <REG52.h>
#include "C51_delay.h"
#include "C51_softiic.h"
#elif defined (_STC12)
#include <STC12X.h>
#include "STC12_delay.h"
#include "STC12_softiic.h"
#elif defined (_STC15)
#include <STC15X.h>
#include "STC15_delay.h"
#include "STC15_softiic.h"
#elif defined (_STC8)
#include <STC8HX.h>
#include "delay.h"
#include "softiic.h"
#else   //STC16
#include <STC16F.h>
#include "delay.h"
#include "softiic.h"
#endif

#define     ADDRESS_DEFAULT                             0x52
#define     SYSRANGE_START                              0x00
#define     SYSTEM_THRESH_HIGH                          0x0C
#define     SYSTEM_THRESH_LOW                           0x0E
#define     SYSTEM_SEQUENCE_CONFIG                      0x01
#define     SYSTEM_RANGE_CONFIG                         0x09
#define     SYSTEM_INTERMEASUREMENT_PERIOD              0x04
#define     SYSTEM_INTERRUPT_CONFIG_GPIO                0x0A
#define     GPIO_HV_MUX_ACTIVE_HIGH                     0x84
#define     SYSTEM_INTERRUPT_CLEAR                      0x0B
#define     RESULT_INTERRUPT_STATUS                     0x13
#define     RESULT_RANGE_STATUS                         0x14
#define     RESULT_CORE_AMBIENT_WINDOW_EVENTS_RTN       0xBC
#define     RESULT_CORE_RANGING_TOTAL_EVENTS_RTN        0xC0
#define     RESULT_CORE_AMBIENT_WINDOW_EVENTS_REF       0xD0
#define     RESULT_CORE_RANGING_TOTAL_EVENTS_REF        0xD4
#define     RESULT_PEAK_SIGNAL_RATE_REF                 0xB6
#define     ALGO_PART_TO_PART_RANGE_OFFSET_MM           0x28
#define     I2C_SLAVE_DEVICE_ADDRESS                    0x8A
#define     MSRC_CONFIG_CONTROL                         0x60
#define     PRE_RANGE_CONFIG_MIN_SNR                    0x27
#define     PRE_RANGE_CONFIG_VALID_PHASE_LOW            0x56
#define     PRE_RANGE_CONFIG_VALID_PHASE_HIGH           0x57
#define     PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT          0x64
#define     FINAL_RANGE_CONFIG_MIN_SNR                  0x67
#define     FINAL_RANGE_CONFIG_VALID_PHASE_LOW          0x47
#define     FINAL_RANGE_CONFIG_VALID_PHASE_HIGH         0x48
#define     FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT 0x44
#define     PRE_RANGE_CONFIG_SIGMA_THRESH_HI            0x61
#define     PRE_RANGE_CONFIG_SIGMA_THRESH_LO            0x62
#define     PRE_RANGE_CONFIG_VCSEL_PERIOD               0x50
#define     PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI          0x51
#define     PRE_RANGE_CONFIG_TIMEOUT_MACROP_LO          0x52
#define     SYSTEM_HISTOGRAM_BIN                        0x81
#define     HISTOGRAM_CONFIG_INITIAL_PHASE_SELECT       0x33
#define     HISTOGRAM_CONFIG_READOUT_CTRL               0x55
#define     FINAL_RANGE_CONFIG_VCSEL_PERIOD             0x70
#define     FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI        0x71
#define     FINAL_RANGE_CONFIG_TIMEOUT_MACROP_LO        0x72
#define     CROSSTALK_COMPENSATION_PEAK_RATE_MCPS       0x20
#define     MSRC_CONFIG_TIMEOUT_MACROP                  0x46
#define     SOFT_RESET_GO2_SOFT_RESET_N                 0xBF
#define     IDENTIFICATION_MODEL_ID                     0xC0
#define     IDENTIFICATION_REVISION_ID                  0xC2
#define     OSC_CALIBRATE_VAL                           0xF8
#define     GLOBAL_CONFIG_VCSEL_WIDTH                   0x32
#define     GLOBAL_CONFIG_SPAD_ENABLES_REF_0            0xB0
#define     GLOBAL_CONFIG_SPAD_ENABLES_REF_1            0xB1
#define     GLOBAL_CONFIG_SPAD_ENABLES_REF_2            0xB2
#define     GLOBAL_CONFIG_SPAD_ENABLES_REF_3            0xB3
#define     GLOBAL_CONFIG_SPAD_ENABLES_REF_4            0xB4
#define     GLOBAL_CONFIG_SPAD_ENABLES_REF_5            0xB5
#define     GLOBAL_CONFIG_REF_EN_START_SELECT           0xB6
#define     DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD         0x4E
#define     DYNAMIC_SPAD_REF_EN_START_OFFSET            0x4F
#define     POWER_MANAGEMENT_GO1_POWER_FORCE            0x80
#define     VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV           0x89
#define     ALGO_PHASECAL_LIM                           0x30
#define     ALGO_PHASECAL_CONFIG_TIMEOUT                0x30

typedef	struct 
{
      uint8 tcc, msrc, dss, pre_range, final_range;
}SequenceStepEnables;

typedef	struct 
{
      uint16 pre_range_vcsel_period_pclks, final_range_vcsel_period_pclks;

      uint16 msrc_dss_tcc_mclks, pre_range_mclks, final_range_mclks;
      uint32 msrc_dss_tcc_us,    pre_range_us,    final_range_us;
}SequenceStepTimeouts;

enum vcselPeriodType { VcselPeriodPreRange, VcselPeriodFinalRange };

uint32 measurement_timing_budget_us;
uint8  stop_variable;
uint8 address;

#define vl53l0x_calc_macroperiod(vcsel_period_pclks) ((((uint32)2304 * (vcsel_period_pclks) * 1655) + 500) / 1000)

uint8  vl53l0x_init();		//vl53l0x初始化，返回1代表初始化成功
void vl53l0x_start_continuous(uint32 period_ms);	//开始连续测量
void vl53l0x_stop_continuous();	//停止连续测量
uint16 vl53l0x_read_range_continuous_millimeters();	//读取连续测量值
uint16 vl53l0x_read_range_single_millimeters();	//读取一次测量结果

//========================================================================
// 描述: vl53l0x写一个寄存器.
// 参数: reg:寄存器;value:写入的值（8位）.
// 返回: none.
//========================================================================
void vl53l0x_write_reg(uint8 reg,uint8 value)
{
    softiic_init();                      //开始信号
    softiic_send_byte(address);   //发送器件写地址
    softiic_wait_ack();
    softiic_send_byte(reg);               //发送寄存器地址
    softiic_wait_ack();
    softiic_send_byte(value);             //发送数据
    softiic_wait_ack();
    softiic_stop();                       //发送停止命令
}

//========================================================================
// 描述: vl53l0x写一个寄存器.
// 参数: reg:寄存器;value:写入的值（16位）.
// 返回: none.
//========================================================================
void vl53l0x_write_reg_16bit(uint8 reg,uint16 value)
{
    softiic_init();                      //开始信号
    softiic_send_byte(address);   //发送器件写地址
    softiic_wait_ack();
    softiic_send_byte(reg);               //发送寄存器地址
    softiic_wait_ack();
    softiic_send_byte((value >> 8) & 0xff);             //发送数据
    softiic_wait_ack();
    softiic_send_byte(value&0xff);             //发送数据
    softiic_wait_ack();
    softiic_stop();                       //发送停止命令
}

//========================================================================
// 描述: vl53l0x写一个寄存器.
// 参数: reg:寄存器;value:写入的值（32位）.
// 返回: none.
//========================================================================
void vl53l0x_write_reg_32bit(uint8 reg,uint32 value)
{
    softiic_start();                      //开始信号
    softiic_send_byte(address);   //发送器件写地址
    softiic_wait_ack();
    softiic_send_byte(reg);               //发送寄存器地址
    softiic_wait_ack();
    softiic_send_byte((value >> 24) & 0xff);             //发送数据
    softiic_wait_ack();
    softiic_send_byte((value >> 16) & 0xff);             //发送数据
    softiic_wait_ack();
    softiic_send_byte((value >> 8) & 0xff);             //发送数据
    softiic_wait_ack();
    softiic_send_byte(value&0xff);             //发送数据
    softiic_wait_ack();
    softiic_stop();                       //发送停止命令
}

//========================================================================
// 描述: vl53l0x读一个寄存器.
// 参数: none.
// 返回: 读取到的数据(8位).
//========================================================================
uint8 vl53l0x_read_reg(uint8 reg)
{
    uint8 value;
    softiic_start();                     //开始信号
    softiic_send_byte(address);      //发送器件写地址
    softiic_wait_ack();
    softiic_send_byte(reg);         //发送寄存器地址
    softiic_wait_ack();
    softiic_stop();

    softiic_start();                        //重复开始信号
    softiic_send_byte(address | 0x01);      //发送器件读地址
    softiic_wait_ack();

    value = softiic_read_byte();
    softiic_nack(); 
    softiic_stop();
	return value;
}

//========================================================================
// 描述: vl53l0x读一个寄存器.
// 参数: none.
// 返回: 读取到的数据(16位).
//========================================================================
uint16 vl53l0x_read_reg_16bit(uint8 reg)
{
    uint16 value;
    uint8 gbuf[2];
    uint8 i;
    for(i = 0; i < 2; i++){
        gbuf[i] = (uint8)vl53l0x_read_reg(reg++);
    }
    value = (uint16)gbuf[0] << 8;
    value |= gbuf[1];
    return value;
}

//========================================================================
// 描述: vl53l0x读一个寄存器.
// 参数: none.
// 返回: 读取到的数据(32位).
//========================================================================
uint16 vl53l0x_read_reg_32bit(uint8 reg)
{
    uint32 value;
    uint8 gbuf[4];
    uint8 i;
    for(i = 0; i < 4; i++){
        gbuf[i] = (uint8)vl53l0x_read_reg(reg++);
    }
    value  = ((uint32)gbuf[0]) << 24;
    value |= ((uint32)gbuf[1]) << 16;
    value |= ((uint16)gbuf[2]) << 8;
    value |= gbuf[3];
    return value;
}

//========================================================================
// 描述: 从传感器读取任意数量的字节，从给定的位置开始.
// 参数: reg:寄存器;dst:读到的数据;count:字节数.
// 返回: none.
//========================================================================
void vl53l0x_read_multi(uint8 reg,uint8 *dst,uint8 count)
{
    softiic_start();                     //开始信号
    softiic_send_byte(address);  //发送器件写地址
    softiic_wait_ack();
    softiic_send_byte(reg);         //发送寄存器地址
    softiic_wait_ack();
    softiic_stop();

    softiic_start();                        //重复开始信号
    softiic_send_byte(address | 0x01);      //发送器件读地址
    softiic_wait_ack();	 

    while(count-- > 0){
        *(dst++) = (uint8)softiic_read_byte();
        softiic_ack(); 
    }
    softiic_stop();  
}

//========================================================================
// 描述: 从给定数组向传感器写入任意数量的字节.
// 参数: reg:寄存器;dst:读到的数据;count:字节数.
// 返回: none.
//========================================================================
void vl53l0x_write_multi(uint8 reg, uint8 const * src, uint8 count)
{
    softiic_start();                      //开始信号
    softiic_send_byte(address);   //发送器件写地址
    softiic_wait_ack();
    softiic_send_byte(reg);               //发送寄存器地址
    softiic_wait_ack();
    while(count-- > 0)
    {
        softiic_send_byte(*(src++));             //发送数据
        softiic_wait_ack();
    }
    softiic_stop();                       //发送停止命令
}

//========================================================================
// 描述: 设置返回信号速率极限检查值，单位为MCPS(百万计数).
// 参数: none.
// 返回: none.
//========================================================================
uint8 vl53l0x_set_signalRateLimit(float limit_Mcps)
{
	  if (limit_Mcps < 0 || limit_Mcps > 511.99) { return 0; }

	  //Q9.7定点格式(9个整数位，7个小数位)
	  vl53l0x_write_reg_16bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT, limit_Mcps * (1 << 7));
	  return 1;
}

//========================================================================
// 描述: 获取MCPS中返回信号速率极限检查值.
// 参数: none.
// 返回: none.
//========================================================================
float vl53l0x_get_signalRateLimit(void)
{
	  return (float)vl53l0x_read_reg_16bit(FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT) / (1 << 7);
}

//========================================================================
// 描述: 获取参考SPAD(单光子雪崩二极管)计数和类型.
// 参数: none.
// 返回: none.
//========================================================================
uint8 vl53l0x_get_spadinfo(uint8_t *count, uint8 * type_is_aperture)
{
	uint8 tmp;
    uint8 i;
	vl53l0x_write_reg(0x80, 0x01);
	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x00, 0x00);

	vl53l0x_write_reg(0xFF, 0x06);
	vl53l0x_write_reg(0x83, vl53l0x_read_reg(0x83) | 0x04);
	vl53l0x_write_reg(0xFF, 0x07);
	vl53l0x_write_reg(0x81, 0x01);

	vl53l0x_write_reg(0x80, 0x01);

	vl53l0x_write_reg(0x94, 0x6b);
	vl53l0x_write_reg(0x83, 0x00);
	i = 0;
	while (vl53l0x_read_reg(0x83) == 0x00)
	{
        i++;
        delay10us();
		if (i >= 250) { return 0; }
	}
	vl53l0x_write_reg(0x83, 0x01);
	tmp = vl53l0x_read_reg(0x92);

	*count = tmp & 0x7f;
	*type_is_aperture = (tmp >> 7) & 0x01;

	vl53l0x_write_reg(0x81, 0x00);
	vl53l0x_write_reg(0xFF, 0x06);
	vl53l0x_write_reg(0x83, vl53l0x_read_reg(0x83)  & ~0x04);
	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x00, 0x01);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x80, 0x00);

	return 1;
}

//========================================================================
// 描述: 获取序列步骤启用.
// 参数: none.
// 返回: none.
//========================================================================
void vl53l0x_get_sequence_step_enables(SequenceStepEnables *enables)
{
	uint8 sequence_config = vl53l0x_read_reg(SYSTEM_SEQUENCE_CONFIG);

	enables->tcc          = (sequence_config >> 4) & 0x1;
	enables->dss          = (sequence_config >> 3) & 0x1;
	enables->msrc         = (sequence_config >> 2) & 0x1;
	enables->pre_range    = (sequence_config >> 6) & 0x1;
	enables->final_range  = (sequence_config >> 7) & 0x1;
}

//========================================================================
// 描述: 获取PCLKs中给定周期类型的VCSEL脉冲周期。.
// 参数: none.
// 返回: none.
//========================================================================
uint8 vl53l0x_get_vcsel_pulse_period(enum vcselPeriodType type)
{
	  if (type == VcselPeriodPreRange)
	  {
		return ((vl53l0x_read_reg(PRE_RANGE_CONFIG_VCSEL_PERIOD)+1)<<1);
	  }
	  else if (type == VcselPeriodFinalRange)
	  {
		return ((vl53l0x_read_reg(FINAL_RANGE_CONFIG_VCSEL_PERIOD)+1)<<1);
	  }
	  else { return 255; }
}
//========================================================================
// 描述: 在PCLKs中，将给定VCSEL周期的序列步长超时从MCLKs转换为微秒.
// 参数: none.
// 返回: none.
//========================================================================
uint32 vl53l0x_timeout_mclks_to_microseconds(uint16 timeout_period_mclks, uint8 vcsel_period_pclks)
{
	uint32 macro_period_ns;
  	macro_period_ns = vl53l0x_calc_macroperiod(vcsel_period_pclks);
	return ((timeout_period_mclks * macro_period_ns) + 500) / 1000;
}

//========================================================================
// 描述: 在PCLKs中，将序列步长超时从微秒转换为给定VCSEL周期的MCLKs.
// 参数: none.
// 返回: none.
//========================================================================
uint32 vl53l0x_timeout_microseconds_to_mclks(uint32 timeout_period_us, uint8 vcsel_period_pclks)
{
	uint32 macro_period_ns;
    macro_period_ns = vl53l0x_calc_macroperiod(vcsel_period_pclks);
	return (((timeout_period_us * 1000) + (macro_period_ns / 2)) / macro_period_ns);
}


//========================================================================
// 描述: 解码从寄存器值的MCLKs序列步长超时.
// 参数: none.
// 返回: none.
//========================================================================
uint16 vl53l0x_decode_timeout(uint16 reg_val)
{
	  // format: "(LSByte * 2^MSByte) + 1"
	  return (uint16)((reg_val & 0x00FF) <<
			 (uint16)((reg_val & 0xFF00) >> 8)) + 1;
}

//========================================================================
// 描述: 在MCLKs中对timeout中的序列step超时寄存器值进行编码.
// 参数: none.
// 返回: none.
//========================================================================
uint16 vl53l0x_encode_timeout(uint32 timeout_mclks)
{
	  // format: "(LSByte * 2^MSByte) + 1"
	  uint32 ls_byte = 0;
	  uint16 ms_byte = 0;

	  if (timeout_mclks > 0)
	  {
		ls_byte = timeout_mclks - 1;

		while ((ls_byte & 0xFFFFFF00) > 0)
		{
		  ls_byte >>= 1;
		  ms_byte++;
		}

		return (ms_byte << 8) | (ls_byte & 0xFF);
	  }
	  else { return 0; }
}

//========================================================================
// 描述: 获取步骤超时.
// 参数: none.
// 返回: none.
//========================================================================
void vl53l0x_get_sequence_step_timeouts(SequenceStepEnables const * enables, SequenceStepTimeouts * timeouts)
{
	timeouts->pre_range_vcsel_period_pclks = vl53l0x_get_vcsel_pulse_period(VcselPeriodPreRange);

	timeouts->msrc_dss_tcc_mclks = vl53l0x_read_reg(MSRC_CONFIG_TIMEOUT_MACROP) + 1;
	timeouts->msrc_dss_tcc_us =
	vl53l0x_timeout_mclks_to_microseconds(timeouts->msrc_dss_tcc_mclks,
								   (uint8)timeouts->pre_range_vcsel_period_pclks);

	timeouts->pre_range_mclks =
	vl53l0x_decode_timeout(vl53l0x_read_reg_16bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI));
	timeouts->pre_range_us =
	vl53l0x_timeout_mclks_to_microseconds(timeouts->pre_range_mclks,
								   (uint8)timeouts->pre_range_vcsel_period_pclks);

	timeouts->final_range_vcsel_period_pclks = vl53l0x_get_vcsel_pulse_period(VcselPeriodFinalRange);

	timeouts->final_range_mclks =
	vl53l0x_decode_timeout(vl53l0x_read_reg_16bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI));

	if (enables->pre_range)
	{
		timeouts->final_range_mclks -= timeouts->pre_range_mclks;
	}

	timeouts->final_range_us =
	vl53l0x_timeout_mclks_to_microseconds(timeouts->final_range_mclks,
								   (uint8)timeouts->final_range_vcsel_period_pclks);
}

//========================================================================
// 描述: 获取测量时间预算(以微秒为单位).
// 参数: none.
// 返回: none.
//========================================================================
uint32 vl53l0x_get_measurement_timing_budget()
{
	SequenceStepEnables enables;
	SequenceStepTimeouts timeouts;

	uint16 const StartOverhead     = 1910;
	uint16 const EndOverhead        = 960;
    uint16 const MsrcOverhead       = 660;
	uint16 const TccOverhead        = 590;
	uint16 const DssOverhead        = 690;
	uint16 const PreRangeOverhead   = 660;
	uint16 const FinalRangeOverhead = 550;

	// "Start and end overhead times always present"
	uint32 budget_us = StartOverhead + EndOverhead;

	vl53l0x_get_sequence_step_enables(&enables);
	vl53l0x_get_sequence_step_timeouts(&enables, &timeouts);

	if (enables.tcc)
	{
		budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead);
	}

	if (enables.dss)
	{
		budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
	}
	else if (enables.msrc)
	{
		budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
	}

	if (enables.pre_range)
	{
		budget_us += (timeouts.pre_range_us + PreRangeOverhead);
	}

	if (enables.final_range)
	{
		budget_us += (timeouts.final_range_us + FinalRangeOverhead);
	}

	measurement_timing_budget_us = budget_us; // store for internal reuse
	return budget_us;
}

//========================================================================
// 描述: 设置测量时间预算(以微秒为单位).
// 参数: none.
// 返回: none.
//========================================================================
uint8 vl53l0x_set_measurement_timing_budget(uint32 budget_us)
{
	SequenceStepEnables enables;
	SequenceStepTimeouts timeouts;
  	uint32 used_budget_us;
 	uint32 final_range_timeout_us;
 	uint32 final_range_timeout_mclks;
	uint16 const StartOverhead     = 1910;
	uint16 const EndOverhead        = 960;
	uint16 const MsrcOverhead       = 660;
 	uint16 const TccOverhead        = 590;
	uint16 const DssOverhead        = 690;
	uint16 const PreRangeOverhead   = 660;
	uint16 const FinalRangeOverhead = 550;

	uint32 const MinTimingBudget = 20000;

	if (budget_us < MinTimingBudget) { return 0; }

	used_budget_us = StartOverhead + EndOverhead;

	vl53l0x_get_sequence_step_enables(&enables);
	vl53l0x_get_sequence_step_timeouts(&enables, &timeouts);

	if (enables.tcc)
	{
		used_budget_us += (timeouts.msrc_dss_tcc_us + TccOverhead);
	}

	if (enables.dss)
	{
		used_budget_us += 2 * (timeouts.msrc_dss_tcc_us + DssOverhead);
	}
	else if (enables.msrc)
	{
		used_budget_us += (timeouts.msrc_dss_tcc_us + MsrcOverhead);
	}

	if (enables.pre_range)
	{
		used_budget_us += (timeouts.pre_range_us + PreRangeOverhead);
	}

	if (enables.final_range)
	{
		used_budget_us += FinalRangeOverhead;

		// "Note that the final range timeout is determined by the timing
		// budget and the sum of all other timeouts within the sequence.
		// If there is no room for the final range timeout, then an error
		// will be set. Otherwise the remaining time will be applied to
		// the final range."

		if (used_budget_us > budget_us)
		{
		  // "Requested timeout too big."
		  return 0;
		}

	    final_range_timeout_us = budget_us - used_budget_us;

		// set_sequence_step_timeout() begin
		// (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)

		// "For the final range timeout, the pre-range timeout
		//  must be added. To do this both final and pre-range
		//  timeouts must be expressed in macro periods MClks
		//  because they have different vcsel periods."

		final_range_timeout_mclks =
        vl53l0x_timeout_microseconds_to_mclks(final_range_timeout_us,
									 (uint8)(timeouts.final_range_vcsel_period_pclks));

		if (enables.pre_range)
		{
		  final_range_timeout_mclks += timeouts.pre_range_mclks;
		}

		vl53l0x_write_reg_16bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,vl53l0x_encode_timeout(final_range_timeout_mclks));

		// set_sequence_step_timeout() end

		measurement_timing_budget_us = budget_us; // store for internal reuse
	  }
	  return 1;
}

//========================================================================
// 描述: vl53l0x进行一次校准
// 参数: none.
// 返回: none.
//========================================================================
uint8 vl53l0x_perform_single_refcalibration(uint8 vhv_init_byte)
{
  	uint8 i;
	vl53l0x_write_reg(SYSRANGE_START, 0x01 | vhv_init_byte); // VL53L0X_REG_SYSRANGE_MODE_START_STOP
	i = 0;
	while ((vl53l0x_read_reg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
	{
        i++;
        delay10us();
				if (i >= 250) { return 0; }
	}
	vl53l0x_write_reg(SYSTEM_INTERRUPT_CLEAR, 0x01);
	vl53l0x_write_reg(SYSRANGE_START, 0x00);
	return 1;
}	

//========================================================================
// 描述: 设置VCSEL(垂直腔面发射激光器)的脉冲周期.
// 参数: none.
// 返回: none.
//========================================================================
uint8 vl53l0x_set_vcsel_pulse_period(enum vcselPeriodType type, uint8 period_pclks)
{
	uint8 vcsel_period_reg = (period_pclks>>1)-1;

	SequenceStepEnables enables;
	SequenceStepTimeouts timeouts;

	uint16 new_pre_range_timeout_mclks;
	uint16 new_msrc_timeout_mclks;
	uint8 sequence_config;
	uint16 new_final_range_timeout_mclks;
	
	vl53l0x_get_sequence_step_enables(&enables);
	vl53l0x_get_sequence_step_timeouts(&enables, &timeouts);
	// "Apply specific settings for the requested clock period"
	// "Re-calculate and apply timeouts, in macro periods"

	// "When the VCSEL period for the pre or final range is changed,
	// the corresponding timeout must be read from the device using
	// the current VCSEL period, then the new VCSEL period can be
	// applied. The timeout then must be written back to the device
	// using the new VCSEL period.
	//
	// For the MSRC timeout, the same applies - this timeout being
	// dependant on the pre-range vcsel period."

	if (type == VcselPeriodPreRange)
	{
		// "Set phase check limits"
		switch (period_pclks)
		{
		  case 12:
			vl53l0x_write_reg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x18);
			break;

		  case 14:
			vl53l0x_write_reg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x30);
			break;

		  case 16:
			vl53l0x_write_reg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x40);
			break;

		  case 18:
			vl53l0x_write_reg(PRE_RANGE_CONFIG_VALID_PHASE_HIGH, 0x50);
			break;

		  default:
			// invalid period
			return 0;
		}
		vl53l0x_write_reg(PRE_RANGE_CONFIG_VALID_PHASE_LOW, 0x08);

		// apply new VCSEL period
		vl53l0x_write_reg(PRE_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg);

		// update timeouts

		// set_sequence_step_timeout() begin
		// (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE)

		new_pre_range_timeout_mclks = vl53l0x_timeout_microseconds_to_mclks(timeouts.pre_range_us, period_pclks);

		vl53l0x_write_reg_16bit(PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,vl53l0x_encode_timeout(new_pre_range_timeout_mclks));
		// set_sequence_step_timeout() end

		// set_sequence_step_timeout() begin
		// (SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC)

		new_msrc_timeout_mclks = vl53l0x_timeout_microseconds_to_mclks(timeouts.msrc_dss_tcc_us, period_pclks);

		vl53l0x_write_reg(MSRC_CONFIG_TIMEOUT_MACROP,
		  (new_msrc_timeout_mclks > 256) ? 255 : (new_msrc_timeout_mclks - 1));

		// set_sequence_step_timeout() end
	  }
	  else if (type == VcselPeriodFinalRange)
	  {
		switch (period_pclks)
		{
		  case 8:
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x10);
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW,  0x08);
			vl53l0x_write_reg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
			vl53l0x_write_reg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
			vl53l0x_write_reg(0xFF, 0x01);
			vl53l0x_write_reg(ALGO_PHASECAL_LIM, 0x30);
			vl53l0x_write_reg(0xFF, 0x00);
			break;

		  case 10:
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x28);
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW,  0x08);
			vl53l0x_write_reg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
			vl53l0x_write_reg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
			vl53l0x_write_reg(0xFF, 0x01);
			vl53l0x_write_reg(ALGO_PHASECAL_LIM, 0x20);
			vl53l0x_write_reg(0xFF, 0x00);
			break;

		  case 12:
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x38);
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW,  0x08);
			vl53l0x_write_reg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
			vl53l0x_write_reg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
			vl53l0x_write_reg(0xFF, 0x01);
			vl53l0x_write_reg(ALGO_PHASECAL_LIM, 0x20);
			vl53l0x_write_reg(0xFF, 0x00);
			break;

		  case 14:
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_HIGH, 0x48);
			vl53l0x_write_reg(FINAL_RANGE_CONFIG_VALID_PHASE_LOW,  0x08);
			vl53l0x_write_reg(GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
			vl53l0x_write_reg(ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
			vl53l0x_write_reg(0xFF, 0x01);
			vl53l0x_write_reg(ALGO_PHASECAL_LIM, 0x20);
			vl53l0x_write_reg(0xFF, 0x00);
			break;

		  default:
			// invalid period
			return 0;
		}

		// apply new VCSEL period
		vl53l0x_write_reg(FINAL_RANGE_CONFIG_VCSEL_PERIOD, vcsel_period_reg);

		// update timeouts

		// set_sequence_step_timeout() begin
		// (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE)

		// "For the final range timeout, the pre-range timeout
		//  must be added. To do this both final and pre-range
		//  timeouts must be expressed in macro periods MClks
		//  because they have different vcsel periods."

		new_final_range_timeout_mclks = vl53l0x_timeout_microseconds_to_mclks(timeouts.final_range_us, period_pclks);

		if (enables.pre_range)
		{
		  new_final_range_timeout_mclks += timeouts.pre_range_mclks;
		}

		vl53l0x_write_reg_16bit(FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
		vl53l0x_encode_timeout(new_final_range_timeout_mclks));

		// set_sequence_step_timeout end
	  }
	  else
	  {
		// invalid type
		return 0;
	  }

	  // "Finally, the timing budget must be re-applied"

	  vl53l0x_set_measurement_timing_budget(measurement_timing_budget_us);

	  // "Perform the phase calibration. This is needed after changing on vcsel period."
	  // VL53L0X_perform_phase_calibration() begin

	  sequence_config = vl53l0x_read_reg(SYSTEM_SEQUENCE_CONFIG);
	  vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, 0x02);
	  vl53l0x_perform_single_refcalibration(0x0);
	  vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, sequence_config);

	  // VL53L0X_perform_phase_calibration() end

	  return 1;
}

//========================================================================
// 描述: 设置地址.
// 参数: none.
// 返回: none.
//========================================================================
void vl53l0x_set_address(uint8 new_addr)
{
	  vl53l0x_write_reg(I2C_SLAVE_DEVICE_ADDRESS, new_addr & 0x7F);
	  address = new_addr;
}

//========================================================================
// 描述: 开始连续测距.
// 参数: none.
// 返回: none.
//========================================================================
void vl53l0x_start_continuous(uint32 period_ms)
{
	uint16 osc_calibrate_val;
	vl53l0x_write_reg(0x80, 0x01);
	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x00, 0x00);
	vl53l0x_write_reg(0x91, stop_variable);
	vl53l0x_write_reg(0x00, 0x01);
	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x80, 0x00);
	if (period_ms != 0)
	{
		// continuous timed mode

		// VL53L0X_SetInterMeasurementPeriodMilliSeconds() begin

		osc_calibrate_val = vl53l0x_read_reg_16bit(OSC_CALIBRATE_VAL);

		if (osc_calibrate_val != 0)
		{
		  period_ms *= osc_calibrate_val;
		}

		vl53l0x_write_reg_32bit(SYSTEM_INTERMEASUREMENT_PERIOD, period_ms);

		// VL53L0X_SetInterMeasurementPeriodMilliSeconds() end

		vl53l0x_write_reg(SYSRANGE_START, 0x04); // VL53L0X_REG_SYSRANGE_MODE_TIMED
	}
	else
	{
		// continuous back-to-back mode
		vl53l0x_write_reg(SYSRANGE_START, 0x02); // VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK
	}
}

//========================================================================
// 描述: 停止连续测距.
// 参数: none.
// 返回: none.
//========================================================================
void vl53l0x_stop_continuous()
{
	vl53l0x_write_reg(SYSRANGE_START, 0x01); // VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x00, 0x00);
	vl53l0x_write_reg(0x91, 0x00);
	vl53l0x_write_reg(0x00, 0x01);
	vl53l0x_write_reg(0xFF, 0x00);
}


//========================================================================
// 描述: vl53l0x初始化.
// 参数: none.
// 返回: 1,初始化成功；其它值,失败.
//========================================================================
uint8  vl53l0x_init()
{
  	uint8 spad_count;
	uint8 spad_type_is_aperture;
  	uint8 ref_spad_map[6];
	uint8 first_spad_to_enable; // 12 is the first aperture spad
	uint8 spads_enabled;
  	uint8 i;
	address = ADDRESS_DEFAULT;
  	softiic_init();
	if (vl53l0x_read_reg(IDENTIFICATION_MODEL_ID) != 0xEE) { return 0; } //确认ID
	vl53l0x_write_reg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,vl53l0x_read_reg(VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV) | 0x01); // set bit 0

  	//设置I2C标准模式
	vl53l0x_write_reg(0x88, 0x00);
  	vl53l0x_write_reg(0x80, 0x01);
	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x00, 0x00);
	stop_variable = vl53l0x_read_reg(0x91);
  	vl53l0x_write_reg(0x00, 0x01);
	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x80, 0x00);

  	//禁用SIGNAL_RATE_MSRC(第1位)和SIGNAL_RATE_PRE_RANGE(第4位)的限制检查
	vl53l0x_write_reg(MSRC_CONFIG_CONTROL, vl53l0x_read_reg(MSRC_CONFIG_CONTROL) | 0x12);

  	//将最终范围信号速率限制设置为0.25 MCPS(每秒百万次)
	vl53l0x_set_signalRateLimit(0.25);
  	vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, 0xFF);

  	if (!vl53l0x_get_spadinfo(&spad_count, &spad_type_is_aperture)) { return 0; }
 	vl53l0x_read_multi(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
	vl53l0x_write_reg(DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
	vl53l0x_write_reg(0xFF, 0x00);
  	vl53l0x_write_reg(GLOBAL_CONFIG_REF_EN_START_SELECT, 0xB4);

  	first_spad_to_enable = spad_type_is_aperture ? 12 : 0;
  	spads_enabled = 0;
	for (i = 0; i < 48; i++)
	{
		if (i < first_spad_to_enable || spads_enabled == spad_count)
		{
		  // This bit is lower than the first one that should be enabled, or
		  // (reference_spad_count) bits have already been enabled, so zero this bit
		  ref_spad_map[i / 8] &= ~(1 << (i % 8));
		}
		else if ((ref_spad_map[i / 8] >> (i % 8)) & 0x1)
		{
		  spads_enabled++;
		}
	}
  	vl53l0x_write_multi(GLOBAL_CONFIG_SPAD_ENABLES_REF_0, ref_spad_map, 6);

	vl53l0x_write_reg(0xFF, 0x01);
  	vl53l0x_write_reg(0x00, 0x00);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x09, 0x00);
	vl53l0x_write_reg(0x10, 0x00);
	vl53l0x_write_reg(0x11, 0x00);

	vl53l0x_write_reg(0x24, 0x01);
	vl53l0x_write_reg(0x25, 0xFF);
	vl53l0x_write_reg(0x75, 0x00);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x4E, 0x2C);
	vl53l0x_write_reg(0x48, 0x00);
	vl53l0x_write_reg(0x30, 0x20);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x30, 0x09);
	vl53l0x_write_reg(0x54, 0x00);
	vl53l0x_write_reg(0x31, 0x04);
	vl53l0x_write_reg(0x32, 0x03);
	vl53l0x_write_reg(0x40, 0x83);
	vl53l0x_write_reg(0x46, 0x25);
	vl53l0x_write_reg(0x60, 0x00);
	vl53l0x_write_reg(0x27, 0x00);
	vl53l0x_write_reg(0x50, 0x06);
	vl53l0x_write_reg(0x51, 0x00);
	vl53l0x_write_reg(0x52, 0x96);
	vl53l0x_write_reg(0x56, 0x08);
	vl53l0x_write_reg(0x57, 0x30);
	vl53l0x_write_reg(0x61, 0x00);
	vl53l0x_write_reg(0x62, 0x00);
	vl53l0x_write_reg(0x64, 0x00);
	vl53l0x_write_reg(0x65, 0x00);
	vl53l0x_write_reg(0x66, 0xA0);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x22, 0x32);
	vl53l0x_write_reg(0x47, 0x14);
	vl53l0x_write_reg(0x49, 0xFF);
	vl53l0x_write_reg(0x4A, 0x00);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x7A, 0x0A);
	vl53l0x_write_reg(0x7B, 0x00);
	vl53l0x_write_reg(0x78, 0x21);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x23, 0x34);
  	vl53l0x_write_reg(0x42, 0x00);
  	vl53l0x_write_reg(0x44, 0xFF);
  	vl53l0x_write_reg(0x45, 0x26);
	vl53l0x_write_reg(0x46, 0x05);
	vl53l0x_write_reg(0x40, 0x40);
	vl53l0x_write_reg(0x0E, 0x06);
	vl53l0x_write_reg(0x20, 0x1A);
	vl53l0x_write_reg(0x43, 0x40);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x34, 0x03);
	vl53l0x_write_reg(0x35, 0x44);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x31, 0x04);
	vl53l0x_write_reg(0x4B, 0x09);
	vl53l0x_write_reg(0x4C, 0x05);
	vl53l0x_write_reg(0x4D, 0x04);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x44, 0x00);
	vl53l0x_write_reg(0x45, 0x20);
	vl53l0x_write_reg(0x47, 0x08);
	vl53l0x_write_reg(0x48, 0x28);
	vl53l0x_write_reg(0x67, 0x00);
	vl53l0x_write_reg(0x70, 0x04);
	vl53l0x_write_reg(0x71, 0x01);
 	vl53l0x_write_reg(0x72, 0xFE);
  	vl53l0x_write_reg(0x76, 0x00);
	vl53l0x_write_reg(0x77, 0x00);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x0D, 0x01);

	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x80, 0x01);
	vl53l0x_write_reg(0x01, 0xF8);

	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x8E, 0x01);
	vl53l0x_write_reg(0x00, 0x01);
	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x80, 0x00);

	  // "Set interrupt config to new sample ready"
	  // -- VL53L0X_SetGpioConfig() begin

	vl53l0x_write_reg(SYSTEM_INTERRUPT_CONFIG_GPIO, 0x04);
	vl53l0x_write_reg(GPIO_HV_MUX_ACTIVE_HIGH, vl53l0x_read_reg(GPIO_HV_MUX_ACTIVE_HIGH) & ~0x10); // active low
	vl53l0x_write_reg(SYSTEM_INTERRUPT_CLEAR, 0x01);

  	measurement_timing_budget_us = vl53l0x_get_measurement_timing_budget();

  	vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, 0xE8);

  	vl53l0x_set_measurement_timing_budget(measurement_timing_budget_us);

  	vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, 0x01);
  	if (!vl53l0x_perform_single_refcalibration(0x40)) { return 0; }

	vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, 0x02);
	if (!vl53l0x_perform_single_refcalibration(0x00)) { return 0; }

	vl53l0x_write_reg(SYSTEM_SEQUENCE_CONFIG, 0xE8);

	return 1;
}

//========================================================================
// 描述: 在连续模式激活时返回以毫米为单位的范围读数.
// 参数: none.
// 返回: 距离（mm）.
//========================================================================
uint16 vl53l0x_read_range_continuous_millimeters()
{
  	uint16 range;
	uint8 i;
  	i = 0;
	while ((vl53l0x_read_reg(RESULT_INTERRUPT_STATUS) & 0x07) == 0)
	{
    i++;
		delay10us();
		if (i >= 250)
		{
		  //did_timeout = true;
		  return 65535;
		}
	}
	// assumptions: Linearity Corrective Gain is 1000 (default);
	// fractional ranging is not enabled
	range = vl53l0x_read_reg_16bit(RESULT_RANGE_STATUS + 10);
	vl53l0x_write_reg(SYSTEM_INTERRUPT_CLEAR, 0x01);
	return range;
}

//========================================================================
// 描述: 执行一次测距并返回读数.
// 参数: none.
// 返回: 距离（mm）.
//========================================================================
uint16 vl53l0x_read_range_single_millimeters()
{
	uint8 i;
	vl53l0x_write_reg(0x80, 0x01);
	vl53l0x_write_reg(0xFF, 0x01);
	vl53l0x_write_reg(0x00, 0x00);
	vl53l0x_write_reg(0x91, stop_variable);
	vl53l0x_write_reg(0x00, 0x01);
	vl53l0x_write_reg(0xFF, 0x00);
	vl53l0x_write_reg(0x80, 0x00);

	vl53l0x_write_reg(SYSRANGE_START, 0x01);
	i = 0;
	while (vl53l0x_read_reg(SYSRANGE_START) & 0x01)
	{
        i++;
        delay10us();
		if (i >= 250)
		{
		  //did_timeout = true;
		  return 65535;
		}
	}
    return (vl53l0x_read_range_continuous_millimeters()- 30);
}

#endif  // vl53l0.h
